PID to do:
In [1]:
%matplotlib inline
%run -i Device.ipynb
In [2]:
from matplotlib import pyplot,cm
from wernher import Controller
In [13]:
def simulate(xset,
kp,ki,kd,
m,b,k,x0,
g=1,s=0,
total_time=10,freq=10):
npoints = (3*total_time + 1) * freq
dev = Device()
dev.m = m
dev.b = b
dev.k = k
dev.x0 = x0
dev.g = g
dev.s = s
cont = Controller()
cont.kp = kp
cont.ki = ki
cont.kd = kd
cont.cmin = -1
cont.cmax = 1
tt = np.linspace(-1,3*total_time, npoints)
xx0 = np.zeros(tt.shape)
xx0[tt>0] = xset
xx0[tt>total_time] = 0
xx0[tt>2*total_time] = 0.5
xx = [0]
vv = [0]
aa = [0]
t0 = tt[0]
flip = False
for t,x0 in zip(tt[1:],xx0[1:]):
cont.set_point = x0
a = cont(dev.x,t)
x,v = dev(a,t-t0)
aa.append(a)
xx.append(x)
vv.append(v)
t0 = t
return tt, xx0, aa, xx, vv, freq
def plot_simulation(tt,xx0,aa,xx,vv,freq):
fig,ax = pyplot.subplots(1,1,figsize=(14,3))
axr = ax.twinx()
for a,s,c in ([ax,'left','blue'],[axr,'right','red']):
a.spines[s].set_color(c)
a.tick_params(axis='y', colors=c)
a.title.set_color(c)
axr.spines['left'].set_visible(False)
opts = dict(alpha=0.4, lw=4)
ptset, = ax.plot(tt, xx0, color='blue', **opts)
ptval, = ax.plot(tt, xx, color='green', **opts)
ptcont, = axr.plot(tt, aa, color='red', **opts)
ptvel, = axr.plot(tt, vv, color='magenta', **opts)
xmin,xmax = xx0.min(),xx0.max()
dx = xmax - xmin
ax.set_xlim(-1,None)
ax.set_ylim(xmin-dx*0.5,xmax+dx*0.5)
axr.set_ylim(-1.05,1.05)
ax.set_title('Control frequency: {} Hz'.format(freq))
ax.set_xlabel(r'time (s)')
l = ax.legend((ptset,ptcont,ptval,ptvel), ('set point','control','actual','velocity'),
loc='best')
l.set_zorder(1)
In [17]:
for freq in [1,5,10,50,100]: #,500,1000,5000]:
_=plot_simulation(*simulate(xset=1,
kp=1, ki=1, kd=1,
m=1, b=0, k=0, x0=0,
g=1, s=0,
total_time=20, freq=freq))
In [18]:
for freq in [1,5,10,50,100]: #,500,1000,5000]:
_=plot_simulation(*simulate(xset=90*π/180,
kp=1, ki=0.6, kd=1,
m=800, b=0, k=0, x0=0,
g=5000, s=0,
total_time=20, freq=freq))
In [5]:
moi = 1733 # kg m^2
torque = 5000 # kg m^2 / s^2
# We want to be able to rotate at about 3 deg / s
# so 30 deg in 10 seconds
npoints = 100
tt = np.linspace(0,10,npoints)
xx = np.empty((npoints,))
vv = np.empty((npoints,))
cc = np.empty((npoints,))
dev = LinearDevice(t=0, x=-15, v=0, inertia=1733, drag=1, max_force=5000)
con = Controller(set_point=0, kp=1, ki=0.6, kd=1, t0=0)
con.min = -1
con.max = 1
for j,t in enumerate(tt):
c = con(dev.x,t)
x = dev(c,t)
cc[j] = c
xx[j] = x
vv[j] = dev.v
fig,ax = pyplot.subplots()
_=ax.plot(tt,xx, color='blue')
axr = ax.twinx()
_=axr.plot(tt,cc, color='green')
In [184]:
print(xx[-22:-18])
print(cc[-22:-18])
print(vv[-22:-18])
In [18]:
import math
t = 5000
I = 1733
print('Torque = {:.2f} Nm'.format(t))
print('MoI = {:.2f} kg/m^2'.format(I))
setpoint = 45 * (math.pi / 180.0)
O = 0.01
Tp = 3
print('Overshoot = {:.1f}%'.format(O*100))
print('Time to peak = {:.2f} s'.format(Tp))
# tune Kp and Kd
logO = math.log(O)
z = math.sqrt((logO*logO) / (math.pi*math.pi + logO*logO))
w = math.pi / (Tp * math.sqrt(1.0 - z*z))
kp = (I * w * w) / t
kd = (2 * z * w * I) / t
print('z = %.2f' % z)
print('w = %.2f' % w)
print('Kp = %.2f' % kp)
print('Kd = %.2f' % kd)
# run control loop
In [32]:
moi = 1733 # kg m^2
torque = 5000 # kg m^2 / s^2
kkp = np.linspace(0,1,100)
tt = np.linspace(0,10,100)
xx = np.empty((100,100))
cc = np.empty((100,100))
for i,kp in enumerate(kkp):
dev = LinearDevice(t=0, x=10, v=0, inertia=1733, max_force=5000)
con = Controller(set_point=0, kp=kp, kd=0, ki=0, t0=0)
for j,t in enumerate(tt):
c = con(dev.x,t)
x = dev(c,t)
cc[i,j] = c
xx[i,j] = x
pyplot.imshow(xx, extent=[0,10,0,1],origin='lower',aspect='auto')
Out[32]:
In [ ]:
In [102]:
from numpy import tan, arctan, sign
from numpy import pi as π
def control_force(g,s):
if s == 0:
def _fn(c):
return g * c
elif s > 0:
def _fn(c):
return g * arctan(s*c) / arctan(s)
else:
def _fn(c):
return sign(c) * g * (1 - arctan(s*(1-abs(c))) / arctan(s))
return _fn
cc = np.linspace(-1,1,100)
fig,ax = pyplot.subplots()
for s in [-10,-5,-1,-0.1,0,.1,1,5,10]:
ax.plot(cc, control_force(10,s)(cc))
In [31]:
arctan(1) == π/4
Out[31]:
In [30]:
tan(2/π)
Out[30]: